package afcp.alumni.file;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import net.sourceforge.stripes.action.Message;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import afcp.alumni.action.base.BaseAction;
import afcp.alumni.action.base.MyActionBeanContext;
import afcp.alumni.model.Pb;
import afcp.alumni.model.db.Member;
import afcp.alumni.service.FileUploadService;
import afcp.alumni.service.MemberService;
import afcp.alumni.service.UploadService;
import afcp.alumni.util.Conf;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreInputStream;
import com.google.appengine.api.blobstore.BlobstoreService;

@Component
public class UploadServiceBlobstore implements UploadService {

	private static final Log logger = LogFactory.getLog(UploadServiceBlobstore.class);
	
//	@Inject
//	private RoleDao roleDao;
	
//	public String url = "/upload";
	
//	UploadServiceBlobstore(/*String url*/) {
//		this.url = url;
//	}

	@Inject
	private MemberService memberService;

	@Inject
//	@MyBlobstoreService
	private BlobstoreService blobstoreService;

//	public static BlobstoreService blobstoreService = BlobstoreServiceFactory
//			.getBlobstoreService();

	@Override
	public String getUploadUrl(String url) {
		return blobstoreService.createUploadUrl(url);
	}
	
	public static final String UPLOAD_PROBLEM = "message.upload.problem";
	public static final String UPLOAD_INCORRECTHEADER = "message.upload.incorrectHeader";
	
//	private List<Member> memberIndexingBuffer;
	
	
	// TODO les messages de warning/error sur les résultats de l'upload ne
	// s'affichent pas sur le site déployé sur google. à diagnostiquer.
	
	public void deleteUploadedFiles(MyActionBeanContext context) {
		Map<String, List<BlobKey>> blobs = context.getBlobs();
//		List<BlobKey> blobKeys = blobs.get(AdminAction.FORM_FILE_PARAM);
		for (List<BlobKey> blobKeys : blobs.values()) {
			for (BlobKey blobKey : blobKeys) {
				deleteBlob(blobKey);
			}
		}
		
	}
	
	private void deleteBlob(BlobKey blobKey) {
		try {
			blobstoreService.delete(blobKey);
		} catch (Exception e) {
			logger.warn("Can't delete the blob of blobKey: " + blobKey + ". Exception message: " + e.getMessage());
		}
	}
	
	/**
	 * cf {@link ExcelFileUploadService} pour la suite de l'implémentation
	 * Réf pour le parsing Excel :
	 * recherche google : WorkbookFactory.create(inputStream) large files
	 * réponse : http://stackoverflow.com/questions/4897766/processing-large-xlsx-file-in-java
	 */
	@Override
	public List<Message> readUpload(MyActionBeanContext context, AlumniFile file, FileUploadService fileUploadService) {
		
		// If there are problems with large files:
		// http://stackoverflow.com/questions/5522804/1mb-quota-limit-for-a-blobstore-object-in-google-app-engine
		List<Message> failures = new LinkedList<>();

//		Map<String, List<BlobKey>> blobs = blobstoreService
//				.getUploads(request);
		Map<String, List<BlobKey>> blobs = context.getBlobs();
//		List<BlobKey> blobKeys = blobs.get(AdminAction.FORM_FILE_PARAM);
		for (List<BlobKey> blobKeys : blobs.values()) {
			for (BlobKey blobKey : blobKeys) {

//				Transaction txn = memberService.newTransactionObject();
				try {
					
					InputStream inputStream = new BlobstoreInputStream(blobKey);
					
//					memberService.beginTransaction(txn);
					
					fileUploadService.handle(inputStream, file, failures);
					

//					memberService.commitTransaction(txn);

//				} catch (FileNotFoundException e) {
//					logger.error(
//							"The uploaded file corresponding to the BlobKey "
//									+ blobKey
//									+ " has not been found. Please check how the Google Blobstore API is used.",
//							e);
				} catch (IncorrectHeaderException e) {
					logger.warn(
							"The uploaded file has an incorrect header. It seems not to match the expected Member format.");
					failures.add(BaseAction.msgObj(UPLOAD_INCORRECTHEADER));
//					memberService.rollbackTransaction(txn);
				} catch (IOException e) {
					logger.error(
							"A problem occurred while getting the uploaded file corresponding to the BlobKey "
									+ blobKey + ".", e);
					failures.add(BaseAction.msgObj(UPLOAD_PROBLEM));
//					memberService.rollbackTransaction(txn);
				} catch (Exception e) {
					logger.error("A problem occurred while creating the "
							+ "members of the uploaded file corresponding "
							+ "to the BlobKey " + blobKey + ".", e);
					failures.add(BaseAction.msgObj(UPLOAD_PROBLEM));
//					memberService.rollbackTransaction(txn);
				} finally {
//					try {
//						if (memberReader != null)
//							memberReader.close();
//					} catch (IOException e) {
//						logger.warn("Can't close CsvReader", e);
//					}
					deleteBlob(blobKey);
				}
			}
		}
		return failures;
	}
	
//	public static class Uploader {
//		
//		private List<Member> memberIndexingBuffer = new LinkedList<>();
//		
//	}

	@Override
	public void uploadMember(Member member, List<Message> failures, Uploader uploader) {

		String loginId = member.getId();
		List<Member> memberIndexingBuffer = uploader.getMemberIndexingBuffer();
				
		if (member.getErrors() == null) {
//			if (!memberService.memberExists(member)) {
				memberIndexingBuffer.add(member);
//			} else {
//				member.addWarning(Pb.ALREADY_IN_DATABASE);
//			}
			if (memberIndexingBuffer.size() >= Conf.BUFFER_SIZE) {
				sendToDatastore(uploader);
			}
			
//			if (memberService.addMember(member, false)) {
//				memberIndexingBuffer.add(member);
//			}
//			if (memberIndexingBuffer.size() >= bufferSize) {
//				memberService.addToIndex(memberIndexingBuffer);
//				memberIndexingBuffer = new LinkedList<>();
//			}
		}

		if (member.getErrors() != null) {
			for (Pb error : member.getErrors()) {
//				failed.add(BaseAction.msgObj(
//						String.valueOf(problem),
//						member.getFirstName(),
//						member.getLastName(), loginId));
				failures.add(BaseAction.pbToMessage(error,
						member.getFirstName(),
						member.getLastName(), loginId));
			}
		}
		if (member.getWarnings() != null) {
			for (Pb warning : member.getWarnings()) {
				failures.add(BaseAction.pbToMessage(warning,
						member.getFirstName(),
						member.getLastName(), loginId));
			}
		}
		
	}
	
	@Override
	public void flushUploadMember(Uploader uploader) {
		List<Member> memberIndexingBuffer = uploader.getMemberIndexingBuffer();

		if (!memberIndexingBuffer.isEmpty()) {
			sendToDatastore(uploader);
		}
	}
	
	private void sendToDatastore(Uploader uploader) {
		memberService.addOrUpdateMembers(uploader.getMemberIndexingBuffer());
		uploader.setMemberIndexingBuffer(new LinkedList<Member>());
	}
	
//	private void browseMemberReader(MemberReader memberReader, List<Member> failed) {
//		
//		for (Member member : memberReader) {
//			boolean success = memberService.addMember(member);
//			if (!success) {
//				logger.warn("The member "
//						+ member.getFirstName() + " "
//						+ member.getLastName() + " (id: "
//						+ member.getId()
//						+ ") already exists in datastore.");
//				failed.add(member);
//			}
//		}
//		
//	}
//
//	@Override
//	public List<Member> readUpload(HttpServletRequest request,
//			ExcelFileProperties file) {
//		
//		List<Member> failed = new LinkedList<>();
//
//		Map<String, List<BlobKey>> blobs = blobstoreService
//				.getUploads(request);
////		List<BlobKey> blobKeys = blobs.get(AdminAction.FORM_FILE_PARAM);
//		for (List<BlobKey> blobKeys : blobs.values()) {
//			for (BlobKey blobKey : blobKeys) {
//
//				MemberReader memberReader = null;
//				try {
//					
//					InputStream inputStream = new BlobstoreInputStream(blobKey);
//					
//					memberReader = new MemberReader(inputStream, file);
//					
//					browseMemberReader(memberReader, failed);
//
////				} catch (FileNotFoundException e) {
////					logger.error(
////							"The uploaded file corresponding to the BlobKey "
////									+ blobKey
////									+ " has not been found. Please check how the Google Blobstore API is used.",
////							e);
//				} catch (IOException e) {
//					logger.error(
//							"A problem occurred while getting the uploaded file corresponding to the BlobKey "
//									+ blobKey + ".", e);
//				} catch (IncorrectCSVHeaderException e) {
//					logger.error(
//							"The uploaded Excel file has an incorrect header. It seems not to match the expected Member format.",
//							e);
//				} finally {
//					try {
//						if (memberReader != null)
//							memberReader.close();
//					} catch (IOException e) {
//						logger.warn("Can't close MemberReader", e);
//					}
//					blobstoreService.delete(blobKey);
//				}
//			}
//		}
//		return failed;
//	}

}
